#include "tcp_server.h"
#include "libdaq/utils/wrapper_util.h"
#include <memory>

namespace libdaq::backend {

enum class TcpServerAction {
  Connect,
  Disconnect,
  StartAccept,
  StopAccept,
};
DLL_EXPORT uint32_t* CALL_FUNCTION TcpServerWrapper_New(const std::string& ip_address, uint_least16_t port);
DLL_EXPORT void CALL_FUNCTION TcpServerWrapper_Delete(uint32_t* handle);
DLL_EXPORT void CALL_FUNCTION TcpServerWrapper_StartAccept(uint32_t* handle, int duration_ms, bool async, unsigned int client_count);
DLL_EXPORT bool CALL_FUNCTION TcpServerWrapper_IsAcceptComplete(uint32_t* handle);
DLL_EXPORT void CALL_FUNCTION TcpServerWrapper_DisconnectClient(uint32_t* handle, const std::string& ip);
DLL_EXPORT char** CALL_FUNCTION TcpServerWrapper_GetClientsIP(uint32_t* handle, uint8_t& client_count);
DLL_EXPORT uint32_t* CALL_FUNCTION TcpServerWrapper_GetClient(uint32_t* handle, const std::string& ip);


LockzhinerTCPServer* ConvertHandle(uint32_t* handle) {
  return reinterpret_cast<LockzhinerTCPServer*>(handle);
}

uint32_t* ConvertHandle(LockzhinerTCPServer* serverPtr) {
  return reinterpret_cast<uint32_t*>(serverPtr);
}

uint32_t* TcpServerWrapper_New(const std::string& ip_address, uint_least16_t port) {
  return ConvertHandle(new LockzhinerTCPServer(ip_address, port));
}

void TcpServerWrapper_Delete(uint32_t* handle) {
  auto server = ConvertHandle(handle);
  delete server;
  server = nullptr;
}

void TcpServerWrapper_StartAccept(uint32_t* handle, int duration_ms, bool async, unsigned int client_count) {
  auto server = ConvertHandle(handle);
  server->StartAccept(duration_ms, async, client_count);
}

bool TcpServerWrapper_IsAcceptComplete(uint32_t* handle) {
  auto server = ConvertHandle(handle);
  return server->IsAcceptComplete();
}

void TcpServerWrapper_DisconnectClient(uint32_t* handle, const std::string& ip) {
  auto server = ConvertHandle(handle);
  server->DisconnectClient(ip);
}

char** TcpServerWrapper_GetClientsIP(uint32_t* handle, uint8_t& client_count)
{
  auto server = ConvertHandle(handle);
  auto temp_ips = server->GetClientsIP();

  client_count = static_cast<uint8_t>(temp_ips.size());
  char** client_addresses = new char*[client_count];

  for (size_t i = 0; i < client_count; ++i) {
    client_addresses[i] = new char[temp_ips[i].size() + 1];
    strcpy(client_addresses[i], temp_ips[i].c_str());
    client_addresses[i][temp_ips[i].size()] = '\0';
  }

  return client_addresses;
}

uint32_t* TcpServerWrapper_GetClient(uint32_t* handle, const std::string& ip) {
  auto server = ConvertHandle(handle);
  return  reinterpret_cast<uint32_t*>(server->GetClient(ip));
}

} // namespace libdaq::backend